package br.sed.theenemy.presentation.action.json;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSON;
import net.sf.json.JSONSerializer;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

import br.sed.theenemy.presentation.action.json.exception.ExpectedException;
import br.sed.theenemy.presentation.action.json.exception.IdentifiedException;

/**
 * 
 * @author JulioCB
 * @email jcbjulio@gmail.com
 * 
 */
public abstract class JSONBaseAction extends DispatchAction{
 
	private static final long serialVersionUID = -4787412181200997051L;
	
	// cache control headers
    private static final String EXPIRES = "Expires";
    private static final String CACHE_CONTROL = "Cache-Control";
    private static final String CACHE_CONTROLE_NO_CACHE = "no-cache";
    private static final String PRAGMA = "Pragma";
    private static final String PRAGMA_NO_CACHE = "No-cache";
	
    //error
    private static final String UNEXPECTED_ERROR = "1900";
    
    // error array
    private static final String[] UNEXPECT_ERROR_ARRAY = new String[] { UNEXPECTED_ERROR };
    
    // encoding
    private static final String TEXT_HTML_CHARSET_ISO_8859_1 = "text/html; charset=ISO-8859-1";
    private static final String TEXT_HTML_CHARSET = "text/html; charset=";
    private transient String encoding;
    
    //private static final Logger LOGGER = Logger.getLogger(JSONBaseAction.class);
    
	public final ActionForward execute(final ActionMapping map, final ActionForm form, final HttpServletRequest request,
            final HttpServletResponse response) throws IOException {
		
		// set the metadata no-cache in response 
		response.setHeader(PRAGMA, PRAGMA_NO_CACHE);
		response.setHeader(CACHE_CONTROL, CACHE_CONTROLE_NO_CACHE);
		response.setDateHeader(EXPIRES, -1);    
        
        // response contents
        Object content;
        boolean success;
        String[] errors;
        
        try {
            content = executeJSON(map, request, form);
            success = true;
            errors = null;
        } catch (ExpectedException e) {
            success = false;
            content = e.getContent();
            errors = (String[]) e.getErrorIds().clone();
        } catch (IdentifiedException e) {
            success = false;
            content = null;
            errors = new String[] { e.getId() };
        } catch (Exception e) {
            //LOGGER.error("Unexpected error on executeJSON", e);
            success = false;
            content = null;
            errors = UNEXPECT_ERROR_ARRAY;
        }
     
        // set response header
        if (encoding == null){
            response.setContentType(TEXT_HTML_CHARSET_ISO_8859_1);
        } else {
            response.setContentType(TEXT_HTML_CHARSET + encoding);
        }
        
        // serialize response
        final JSONResponse jsonResponse = new JSONResponse(success, content, errors);
        final JSON jsonResponseStr = JSONSerializer.toJSON(jsonResponse);

        // write JSON object to response
        final PrintWriter writer = response.getWriter();
        writer.println(jsonResponseStr);
        
        writer.close();
        
        return null;
        
	}	
	
	/**
     * Method should be extended in child classes and contain the 
     * features of the Action.
     * 
     * @param request HttpServletRequest
     * @return Information that might possibly need to be part of
     *         the result.<br>
     *         The data returned will be displayed
     * @throws ExpectedException Exceptions that the front end is ready to receive
     * @throws IdentifiedException IdentifiedException
     */
	protected abstract Object executeJSON(final ActionMapping mapping, 
            final HttpServletRequest request, final ActionForm form)
            throws ExpectedException, IdentifiedException;
    
    /**
     * Sets the encoding of the response. It should be called in the child classes who 
     * wish to change the ISO-8859-1 in response.
     * 
     * @param encoding  Code of the desired charset, eg ISO-8859-1, UTF-8.
     */
    protected final void setEncoding(final String encoding) {
        this.encoding = encoding;
    }
}
